import { _decorator } from 'cc'
import Singleton from '../Base/Singleton'
import { ApiMsgEnum, binaryDecode, binaryEncode, ICallApiret, IItem, IModel, strdecode } from '../Common'

const address = `ws://localhost`
// 网络连接管理
export class NetworkManager extends Singleton {
  static get Instance() {
    return super.GetInstance<NetworkManager>()
  }
  isConnected = false
  port = 9875
  ws: WebSocket
  // 事件集合
  private map: Map<ApiMsgEnum, Array<IItem>> = new Map()

  // 建立连接
  connect() {
    return new Promise((resolve, reject) => {
      if (this.isConnected) return resolve(true)

      this.ws = new WebSocket(`${address}:${this.port}`)
      // socket返回值类型设置 blob/arraybuffer
      this.ws.binaryType = 'arraybuffer'
      this.ws.onopen = () => {
        this.isConnected = true
        resolve(true)
      }
      this.ws.onclose = () => {
        this.isConnected = false
        reject(false)
      }
      this.ws.onerror = e => {
        this.isConnected = false
        console.log(e)
        reject(false)
      }
      this.ws.onmessage = e => {
        try {
          const json = binaryDecode(e.data)
          // const ta = new Uint8Array(e.data)
          // const str = strdecode(ta)
          // const json = JSON.parse(str)
          const { name, data } = json

          // 事件触发
          if (this.map.has(name)) {
            this.map.get(name).forEach(({ cb, ctx }) => {
              cb.call(ctx, data)
            })
          }
        } catch (error) {
          console.log(error)
        }
      }
    })
  }

  // 模拟api服务
  callApi<T extends keyof IModel['api'] /*泛型约束*/>(name: T, data: IModel['api'][T]['req']): Promise<ICallApiret<IModel['api'][T]['res']>> {
    return new Promise(resolve => {
      try {
        const timer = setTimeout(() => {
          resolve({ success: false, error: new Error('Time out!') })
          this.unListenMsg(name as any, cb, null)
        }, 5000)

        const cb = res => {
          resolve(res)
          clearTimeout(timer)
          this.unListenMsg(name as any, cb, null)
        }

        this.listenMsg(name as any, cb, null)
        this.sendMsg(name as any, data)
      } catch (error) {
        resolve({ success: false, error })
      }
    })
  }

  // 发送信息给服务端
  async sendMsg<T extends keyof IModel['msg']>(name: T, data: IModel['msg'][T]) {
    // const obj = {
    //   name,
    //   data,
    // }
    // const str = JSON.stringify(obj)
    // const ta = strencode(str)
    // const ab = new ArrayBuffer(ta.length)
    // const da = new DataView(ab)
    // for (let index = 0; index < ta.length; index++) {
    //   da.setUint8(index, ta[index])
    // }

    // 压缩包体
    const da = binaryEncode(name, data)

    // await new Promise(rs => setTimeout(rs, 1000))
    this.ws.send(da.buffer)
  }
  // 事件监听
  listenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void, ctx: unknown) {
    if (this.map.has(name)) {
      this.map.get(name).push({ cb, ctx })
    } else {
      this.map.set(name, [{ cb, ctx }])
    }
  }
  // 事件解绑
  unListenMsg<T extends keyof IModel['msg']>(name: T, cb: (args: IModel['msg'][T]) => void, ctx: unknown) {
    if (this.map.has(name)) {
      const index = this.map.get(name).findIndex(i => cb === i.cb && i.ctx === ctx)
      index > -1 && this.map.get(name).splice(index, 1)
    }
  }
}
